﻿// ********************************************************************
//  文件名: MyAsync.cs
//  描述:
//  作者: 胡宇辰
//  创建时间: 2024-5-9
// 
//  修改历史:
// ********************************************************************

using System.Net;
using System.Net.Sockets;
using System.Text;

namespace MyApp;

public class MyAsync
{
    static Socket socket;
    static SocketAsyncEventArgs args = new();
    private static byte[] sendBuffer = new byte[1024];
    static SocketAsyncEventArgs receiveArgs = new();
    private static byte[] receiveBuffer = new byte[1024];
    public static void Enter()
    {
        //客户端利用socket连接服务器
        socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        IPEndPoint pt = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6324);
        args.Completed += IO_Completed;
        args.RemoteEndPoint = pt;
        bool suspend = socket.ConnectAsync(args);
        if(suspend == false) 
            ProcessConnect(args);
    }
    
    static void ProcessConnect(SocketAsyncEventArgs e)
    {
        var client = e.ConnectSocket;
        Console.WriteLine($"Connect Success");
        e.UserToken = client;
        e.SetBuffer(sendBuffer, 0, sendBuffer.Length);

        receiveArgs.UserToken = client;
        receiveArgs.Completed += IO_Completed;
        receiveArgs.SetBuffer(receiveBuffer, 0, 1024);
        if (!client.ReceiveAsync(receiveArgs))
        {
            ProcessReceive(receiveArgs);
        }
        
        while (true)
        {
            string content = Console.ReadLine();
            if (content != "close")
            {
                var bytes = Encoding.UTF8.GetBytes(content);
                Array.Copy(bytes, 0, sendBuffer, 0, bytes.Length);
                e.SetBuffer(0, bytes.Length);
                client.SendAsync(e);
                Console.WriteLine($"Send Success Thread:{Thread.CurrentThread.ManagedThreadId}");
                continue;
            }
            try
            {
                socket.Shutdown(SocketShutdown.Send);
            }
            // throws if client process has already closed
            catch (Exception) { }
            socket.Close();
            return;
        }   
    }

    static void ProcessReceive(SocketAsyncEventArgs e)
    {
        var client = (Socket)e.UserToken;
        string content = Encoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred);
        Console.WriteLine($"Receive {content}; Thread:{Thread.CurrentThread.ManagedThreadId}");
        if (!client.ReceiveAsync(e))
        {
            ProcessReceive(e);
        }
    }
    
    static void IO_Completed(object? sender, SocketAsyncEventArgs saea) {
        if (saea.SocketError == SocketError.Success)
        {
            switch(saea.LastOperation) 
            {
                case SocketAsyncOperation.Connect:
                    ProcessConnect(saea);
                    break;
                case SocketAsyncOperation.Receive:
                    ProcessReceive(saea);
                    break;
            }
        }
        else
        {
            Console.WriteLine("SocketError:" + saea.SocketError);
        }
    }
}